Матч 379, Заполнение коробки (FillBox)

Дивизион 1, Уровень 2

 

Имеется коробка размера length * width * height, которую необходимо заполнить кубами. Длины сторон имеющихся кубов являются степенями двойки (1*1*1, 2*2*2, 4*4*4, 8*8*8,  …). В массиве cubes ячейка cubes[i] (i = 0, 1, 2, …) содержит количество имеющихся у Вас кубов размера 2i * 2i * 2i. Найти наименьшее количество кубов, которыми можно полностью уложить коробку размера length * width * height. Вернуть -1, если этого совершить невозможно.

 

Класс: FillBox

Метод: int minCubes(int length, int width, int height,

                    vector<int> cubes)

Ограничения: 1 £ length, width, height £ 106, cubes содержит от 1 до 20 элементов, 1 £ cubes[i] £ 106.

 

Вход. Размеры коробки length, width, height, а также массив cubes, описывающий имеющиеся в наличии кубы.

 

Выход. Наименьшее количество кубов, которыми можно полностью уложить коробку.

 

Пример входа

length

width

height

cubes

4

4

8

{10,10,10}

4

4

8

{10,10,1}

10

10

11

{1099}

 

Пример выхода

2

9

-1

 

 

РЕШЕНИЕ

жадный алгоритм

 

Если коробка имеет размер length * width * height, а сторона куба равна len = 2i, то в коробку можно вложить максимум amount =  (length / len) * (width / len) * (height / len) таких кубов. При этом если amount > cubes[i], то мы можем использовать максимум cubes[i] кубов (только те кубы, которые имеются в наличии).

Очевидно, что в коробку следует сначала складывать самые большие кубы. Когда  имеющиеся в наличии кубы закончатся или очередной куб нельзя будет вложить в коробку, следует перейти к вкладыванию в коробку следующих по убыванию размера кубов. Продолжаем процесс складывания до тех пор, пока не будет иметь место одно из условий:

а) коробка будет полностью заполнена;

б) все имеющиеся кубы будут вложены в коробку;

в) ни один из оставшихся кубов нельзя вложить в коробку;

Пусть уже сложено в коробку done кубов размера 2i. Известно, что в куб размера 2i можно вложить 8 кубов размера 2i-1. Тогда при последующем вкладывании кубов размера 2i-1 будем считать, что в коробку уже вложено 8*done кубов размера 2i-1.

 

ПРОГРАММА

 

#include <cstdio>

#include <vector>

using namespace std;

 

class FillBox

{

public:

  int minCubes(int length, int width, int height, vector<int> cubes)

  {

    long long done = 0, res = 0;

    for (int i = cubes.size() - 1; i >= 0; i--)

    {

      int len = 1 << i;

      int amount = (length / len) * (width / len) * (height / len);

      amount -= done;

      if (amount > cubes[i]) amount = cubes[i];

      done = (done + amount) * 8;

      res += amount;

    }

    if (done < 8LL * length * width * height) return -1;

    return res;

  }

};